home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mgr / sparcmgr / demo2.zoo / demo / ex / expreserve.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-08-06  |  8.0 KB  |  401 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6.  
  7. #ifndef lint
  8. char *copyright =
  9. "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  10.  All rights reserved.\n";
  11. #endif not lint
  12.  
  13. #ifndef lint
  14. static char *sccsid = "@(#)expreserve.c    7.13 (Berkeley) 1/22/86; 1.3 (Bellcore)    86/08/06";
  15. #endif not lint
  16.  
  17. #include <stdio.h>
  18. #include <ctype.h>
  19. #include <sys/param.h>
  20. #include <sys/stat.h>
  21. #include <sys/dir.h>
  22. #include <pwd.h>
  23. #include "uparm.h"
  24.  
  25. #define TMP    "/tmp"
  26.  
  27. #ifdef VMUNIX
  28. #define    HBLKS    2
  29. #else
  30. #define HBLKS    1
  31. #endif
  32.  
  33. char xstr[1];            /* make loader happy */
  34.  
  35. /*
  36.  * Expreserve - preserve a file in usrpath(spool/preserve)
  37.  * Bill Joy UCB November 13, 1977
  38.  *
  39.  * This routine is very naive - it doesn't remove anything from
  40.  * usrpath(spool/preserve)... this may mean that we leave
  41.  * stuff there... the danger in doing anything with usrpath(spool/preserve)
  42.  * is that the clock may be screwed up and we may get confused.
  43.  *
  44.  * We are called in two ways - first from the editor with no argumentss
  45.  * and the standard input open on the temp file. Second with an argument
  46.  * to preserve the entire contents of /tmp (root only).
  47.  *
  48.  * BUG: should do something about preserving Rx... (register contents)
  49.  *      temporaries.
  50.  */
  51.  
  52. #ifndef VMUNIX
  53. #define    LBLKS    125
  54. #else
  55. #define    LBLKS    900
  56. #endif
  57. #define    FNSIZE    128
  58.  
  59. struct     header {
  60.     time_t    Time;            /* Time temp file last updated */
  61.     int    Uid;            /* This users identity */
  62. #ifndef VMUNIX
  63.     short    Flines;            /* Number of lines in file */
  64. #else
  65.     int    Flines;
  66. #endif
  67.     char    Savedfile[FNSIZE];    /* The current file name */
  68.     short    Blocks[LBLKS];        /* Blocks where line pointers stashed */
  69. } H;
  70.  
  71. #ifdef    lint
  72. #define    ignore(a)    Ignore(a)
  73. #define    ignorl(a)    Ignorl(a)
  74. #else
  75. #define    ignore(a)    a
  76. #define    ignorl(a)    a
  77. #endif
  78.  
  79. struct    passwd *getpwuid();
  80. off_t    lseek();
  81. FILE    *popen();
  82.  
  83. #define eq(a, b) strcmp(a, b) == 0
  84.  
  85. main(argc)
  86.     int argc;
  87. {
  88.     register DIR *tf;
  89.     struct direct *dirent;
  90.     struct stat stbuf;
  91.  
  92.     /*
  93.      * If only one argument, then preserve the standard input.
  94.      */
  95.     if (argc == 1) {
  96.         if (copyout((char *) 0))
  97.             exit(1);
  98.         exit(0);
  99.     }
  100.  
  101.     /*
  102.      * If not super user, then can only preserve standard input.
  103.      */
  104.     if (getuid()) {
  105.         fprintf(stderr, "NOT super user\n");
  106.         exit(1);
  107.     }
  108.  
  109.     /*
  110.      * ... else preserve all the stuff in /tmp, removing
  111.      * it as we go.
  112.      */
  113.     if (chdir(TMP) < 0) {
  114.         perror(TMP);
  115.         exit(1);
  116.     }
  117.  
  118.     tf = opendir(".");
  119.     if (tf == NULL) {
  120.         perror(TMP);
  121.         exit(1);
  122.     }
  123.     while ((dirent = readdir(tf)) != NULL) {
  124.         /* Ex temporaries must begin with Ex. */
  125.         if (dirent->d_name[0] != 'E' || dirent->d_name[1] != 'x')
  126.             continue;
  127.         if (stat(dirent->d_name, &stbuf))
  128.             continue;
  129.         if ((stbuf.st_mode & S_IFMT) != S_IFREG)
  130.             continue;
  131.         /*
  132.          * Save the bastard.
  133.          */
  134.         ignore(copyout(dirent->d_name));
  135.     }
  136.     closedir(tf);
  137.     exit(0);
  138. }
  139.  
  140. char    pattern[] =    usrpath(spool/preserve/Exaa`XXXXX);
  141.  
  142. /*
  143.  * Copy file name into usrpath(spool/preserve)/...
  144.  * If name is (char *) 0, then do the standard input.
  145.  * We make some checks on the input to make sure it is
  146.  * really an editor temporary, generate a name for the
  147.  * file (this is the slowest thing since we must stat
  148.  * to find a unique name), and finally copy the file.
  149.  */
  150. copyout(name)
  151.     char *name;
  152. {
  153.     int i;
  154.     static int reenter;
  155.     char buf[BUFSIZ];
  156.  
  157.     /*
  158.      * The first time we put in the digits of our
  159.      * process number at the end of the pattern.
  160.      */
  161.     if (reenter == 0) {
  162.         mkdigits(pattern);
  163.         reenter++;
  164.     }
  165.  
  166.     /*
  167.      * If a file name was given, make it the standard
  168.      * input if possible.
  169.      */
  170.     if (name != 0) {
  171.         ignore(close(0));
  172.         /*
  173.          * Need read/write access for arcane reasons
  174.          * (see below).
  175.          */
  176.         if (open(name, 2) < 0)
  177.             return (-1);
  178.     }
  179.  
  180.     /*
  181.      * Get the header block.
  182.      */
  183.     ignorl(lseek(0, 0l, 0));
  184.     if (read(0, (char *) &H, sizeof H) != sizeof H) {
  185. format:
  186.         if (name == 0)
  187.             fprintf(stderr, "Buffer format error\t");
  188.         return (-1);
  189.     }
  190.  
  191.     /*
  192.      * Consistency checsks so we don't copy out garbage.
  193.      */
  194.     if (H.Flines < 0) {
  195. #ifdef DEBUG
  196.         fprintf(stderr, "Negative number of lines\n");
  197. #endif
  198.         goto format;
  199.     }
  200.     if (H.Blocks[0] != HBLKS || H.Blocks[1] != HBLKS+1) {
  201. #ifdef DEBUG
  202.         fprintf(stderr, "Blocks %d %d\n", H.Blocks[0], H.Blocks[1]);
  203. #endif
  204.         goto format;
  205.     }
  206.     if (name == 0 && H.Uid != getuid()) {
  207. #ifdef DEBUG
  208.         fprintf(stderr, "Wrong user-id\n");
  209. #endif
  210.         goto format;
  211.     }
  212.     if (lseek(0, 0l, 0)) {
  213. #ifdef DEBUG
  214.         fprintf(stderr, "Negative number of lines\n");
  215. #endif
  216.         goto format;
  217.     }
  218.  
  219.     /*
  220.      * If no name was assigned to the file, then give it the name
  221.      * LOST, by putting this in the header.
  222.      */
  223.     if (H.Savedfile[0] == 0) {
  224.         strcpy(H.Savedfile, "LOST");
  225.         ignore(write(0, (char *) &H, sizeof H));
  226.         H.Savedfile[0] = 0;
  227.         lseek(0, 0l, 0);
  228.     }
  229.  
  230.     /*
  231.      * File is good.  Get a name and create a file for the copy.
  232.      */
  233.     mknext(pattern);
  234.     ignore(close(1));
  235.     if (creat(pattern, 0600) < 0) {
  236.         if (name == 0)
  237.             perror(pattern);
  238.         return (1);
  239.     }
  240.  
  241.     /*
  242.      * Make the target be owned by the owner of the file.
  243.      */
  244.     ignore(chown(pattern, H.Uid, 0));
  245.  
  246.     /*
  247.      * Copy the file.
  248.      */
  249.     for (;;) {
  250.         i = read(0, buf, BUFSIZ);
  251.         if (i < 0) {
  252.             if (name)
  253.                 perror("Buffer read error");
  254.             ignore(unlink(pattern));
  255.             return (-1);
  256.         }
  257.         if (i == 0) {
  258.             if (name)
  259.                 ignore(unlink(name));
  260.             notify(H.Uid, H.Savedfile, (int) name, H.Time);
  261.             return (0);
  262.         }
  263.         if (write(1, buf, i) != i) {
  264.             if (name == 0)
  265.                 perror(pattern);
  266.             unlink(pattern);
  267.             return (-1);
  268.         }
  269.     }
  270. }
  271.  
  272. /*
  273.  * Blast the last 5 characters of cp to be the process number.
  274.  */
  275. mkdigits(cp)
  276.     char *cp;
  277. {
  278.     register int i, j;
  279.  
  280.     for (i = getpid(), j = 5, cp += strlen(cp); j > 0; i /= 10, j--)
  281.         *--cp = i % 10 | '0';
  282. }
  283.  
  284. /*
  285.  * Make the name in cp be unique by clobbering up to
  286.  * three alphabetic characters into a sequence of the form 'aab', 'aac', etc.
  287.  * Mktemp gets weird names too quickly to be useful here.
  288.  */
  289. mknext(cp)
  290.     char *cp;
  291. {
  292.     char *dcp;
  293.     struct stat stb;
  294.  
  295.     dcp = cp + strlen(cp) - 1;
  296.     while (isdigit(*dcp))
  297.         dcp--;
  298. whoops:
  299.     if (dcp[0] == 'z') {
  300.         dcp[0] = 'a';
  301.         if (dcp[-1] == 'z') {
  302.             dcp[-1] = 'a';
  303.             if (dcp[-2] == 'z')
  304.                 fprintf(stderr, "Can't find a name\t");
  305.             dcp[-2]++;
  306.         } else
  307.             dcp[-1]++;
  308.     } else
  309.         dcp[0]++;
  310.     if (stat(cp, &stb) == 0)
  311.         goto whoops;
  312. }
  313.  
  314. /*
  315.  * Notify user uid that his file fname has been saved.
  316.  */
  317. notify(uid, fname, flag, time)
  318.     int uid;
  319.     char *fname;
  320.     time_t    time;
  321. {
  322.     struct passwd *pp = getpwuid(uid);
  323.     register FILE *mf;
  324.     char    cmd[BUFSIZ];
  325.     char    hostname[128];
  326.     char    croak[128];
  327.     char    *timestamp, *ctime();
  328.  
  329.     if (pp == NULL)
  330.         return;
  331.     gethostname(hostname, sizeof(hostname));
  332.     timestamp = ctime(&time);
  333.     timestamp[16] = 0;    /* blast from seconds on */
  334.     sprintf(cmd, "/bin/mail %s", pp->pw_name);
  335.     setuid(getuid());
  336.     mf = popen(cmd, "w");
  337.     if (mf == NULL)
  338.         return;
  339.     setbuf(mf, cmd);
  340.     /*
  341.      *    flag says how the editor croaked:
  342.      * "the editor was killed" is perhaps still not an ideal
  343.      * error message.  Usually, either it was forcably terminated
  344.      * or the phone was hung up, but we don't know which.
  345.      */
  346.     sprintf(croak, flag
  347.         ? "the system went down"
  348.         : "the editor was killed");
  349.     if (fname[0] == 0) {
  350.         fname = "LOST";
  351.         fprintf(mf,
  352. "Subject: editor saved ``LOST''\n");
  353.         fprintf(mf,
  354. "You were editing a file without a name\n");
  355.         fprintf(mf,
  356. "at <%s> on the machine ``%s'' when %s.\n", timestamp, hostname, croak);
  357.         fprintf(mf,
  358. "Since the file had no name, it has been named \"LOST\".\n");
  359.     } else {
  360.         fprintf(mf,
  361. "Subject: editor saved ``%s''\n", fname);
  362.         fprintf(mf,
  363. "You were editing the file \"%s\"\n", fname);
  364.         fprintf(mf,
  365. "at <%s> on the machine ``%s''\n", timestamp, hostname);
  366.         fprintf(mf,
  367. "when %s.\n", croak);
  368.     }
  369.     fprintf(mf,
  370. "\nYou can retrieve most of your changes to this file\n");
  371.     fprintf(mf,
  372. "using the \"recover\" command of the editor.\n");
  373.     fprintf(mf,
  374. "An easy way to do this is to give the command \"vi -r %s\".\n", fname);
  375.     fprintf(mf,
  376. "This method also works using \"ex\" and \"edit\".\n");
  377.     pclose(mf);
  378. }
  379.  
  380. /*
  381.  *    people making love
  382.  *    never exactly the same
  383.  *    just like a snowflake 
  384.  */
  385.  
  386. #ifdef lint
  387. Ignore(a)
  388.     int a;
  389. {
  390.  
  391.     a = a;
  392. }
  393.  
  394. Ignorl(a)
  395.     long a;
  396. {
  397.  
  398.     a = a;
  399. }
  400. #endif
  401.